/*****************************************************************
myd engine v0.1

File: myd_vertexbuffer.inl
Created: 26/05/09
*****************************************************************/
//-----------------------------------------------------------------create
template <class VertexFormat, unsigned int FVF>
bool Vertexbuffer<VertexFormat,FVF>::create(IDirect3DDevice9* D3Ddevice, bool bDynamic)
{
	//create the vertex buffer
	HRESULT hr = D3Ddevice->CreateVertexBuffer(
  											uiVBOSize * sizeof(VertexFormat),
											(bDynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : 0),
											FVF,
											D3DPOOL_DEFAULT, 
											&wn_VBO,
											NULL
	);
	
	wn_D3Ddevice = D3Ddevice;

	return (hr == D3D_OK);
}
//-----------------------------------------------------------------bind
template<class VertexFormat, unsigned int FVF>
void Vertexbuffer<VertexFormat,FVF>::bind(void) const
{
	HRESULT hr = wn_D3Ddevice->SetVertexShader(NULL);
	hr = wn_D3Ddevice->SetFVF(FVF);
	hr = wn_D3Ddevice->SetStreamSource(0, wn_VBO, NULL,	sizeof(VertexFormat));
}
//-----------------------------------------------------------------flush
template <class VertexFormat, unsigned int FVF>
void Vertexbuffer<VertexFormat,FVF>::flush(void)
{
	unsigned int uiPrimitiveCount = 0;

	//check the primitive type
	if (m_ePrimitiveType == D3DPT_TRIANGLELIST)
		uiPrimitiveCount = uiVertexToLock / 3;
	else if (m_ePrimitiveType == D3DPT_TRIANGLESTRIP)
		uiPrimitiveCount = uiVertexToLock - 2;
	else
	{assert(0);}

	HRESULT hr = wn_D3Ddevice->DrawPrimitive(m_ePrimitiveType, uiBase, uiPrimitiveCount);

	assert(hr == D3D_OK);
}
//-----------------------------------------------------------------draw
template<class VertexFormat, unsigned int FVF>
void Vertexbuffer<VertexFormat,FVF>::draw(const VertexFormat* vertices, 
	    									D3DPRIMITIVETYPE ePrimitive, 
											unsigned int uiVertexCount)
{
	m_ePrimitiveType = ePrimitive;

	//check the VBO limit
	if(uiFlush < uiVertexCount)
		uiVertexToLock = uiFlush;
	else
		uiVertexToLock = uiVertexCount;
	
	//reset counter
	if(uiBase + uiVertexToLock > uiVBOSize)
		uiBase = 0;
	
	//lock the VBO
	void* pvVertices = NULL;
	HRESULT hr = wn_VBO->Lock(uiBase * sizeof(VertexFormat),
							  uiVertexToLock * sizeof(VertexFormat),
							  (void**)(&pvVertices),
							  uiBase ? D3DLOCK_NOOVERWRITE: D3DLOCK_DISCARD
	);

	unsigned int uiVertexProcNow = 0;

	while(uiVertexToLock > 0)
	{
		//copy the vertices
		memcpy(
			  pvVertices, 
			  &vertices[uiVertexProcNow], 
			  sizeof(VertexFormat) * uiVertexToLock
		); 
		
		uiVertexProcNow += uiVertexToLock;

		//unlock the vertex buffer
		hr = wn_VBO->Unlock();

		//flush all the vertices
		flush();

		//update the counters
		uiBase += uiVertexToLock;

		if(uiFlush < (uiVertexCount - uiVertexProcNow))
			uiVertexToLock = uiFlush;
		else
			uiVertexToLock = uiVertexCount - uiVertexProcNow;
		
		//reset the base
		if (uiBase + uiVertexToLock > uiVBOSize)
			uiBase = 0;

		//lock the VBO
		hr = wn_VBO->Lock(
						 uiBase * sizeof(VertexFormat),
						 uiVertexToLock * sizeof(VertexFormat),
					 	 (void**)(&vertices),
						 uiBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD
		); 
	}		

	//unlock the buffer
	wn_VBO->Unlock();
}
//-----------------------------------------------------------------release
template<class VertexFormat, unsigned int FVF>
void Vertexbuffer<VertexFormat,FVF>::release(void)
{
}
//-----------------------------------------------------------------
template<class VertexFormat, unsigned int FVF>
Vertexbuffer<VertexFormat,FVF>::Vertexbuffer(void)
:
wn_VBO(NULL),
wn_D3Ddevice(NULL),
uiVBOSize(400), 
uiBase(0),
uiVertexToLock(0)
{
}
//-----------------------------------------------------------------~
template<class VertexFormat, unsigned int FVF>
Vertexbuffer<VertexFormat,FVF>::~Vertexbuffer(void)
{
}
